package practica3c;

import java.util.Comparator;
import java.util.Random;

import practica3c.Arbol.tipoLlenado;

public class Cromosoma {
	
	private Arbol genotipo;
	private int edad;
	private int numCopias;
	private tipoLlenado tipo_llenado;
	private int altura_max;
	private int aptitud;
	
	public Cromosoma(tipoLlenado tipo_llenado, int altura_max){
		this.tipo_llenado = tipo_llenado;
		this.altura_max = altura_max;
		Random r = new Random();
		int val = r.nextInt(4);
		String dato = null;
		switch(val){
			case 0:
				dato = "AND";
				break;
			case 1:
				dato = "OR";
				break;
			case 2:
				dato = "NOT";
				break;
			case 3: default:
				dato = "IF";
		}
		genotipo = new Arbol(null,dato);
		edad = 0;
		numCopias = 1;
	}

	public Cromosoma(Cromosoma c){
		genotipo = new Arbol(c.genotipo,0);
		aptitud = c.aptitud;
		tipo_llenado = c.tipo_llenado;
		altura_max = c.altura_max;
		edad = 0;
		numCopias = 1;
	}
		
	public Arbol getPuntoCrucePadre(int altura_cruce){
		return  genotipo.getPuntoCrucePadre(altura_cruce);
	}
	
	public void aumentarCopias(){
		numCopias++;
	}
	
	public void resetCopias(){
		numCopias = 0;
	}
	
	public int getCopias(){
		return numCopias;
	}
	
	public void aumentarEdad(){
		edad++;
	}
	
	public int getEdad(){
		return edad;
	}
	
	public void resetEdad(){
		edad = 0;
	}
	
	public Cromosoma clone(){
		return new Cromosoma(this);
	}

	public void setGenotipo(Arbol gen) {
		genotipo = gen;
		recalcularAptitud2();
	}

	public String getGenoString(){
		return genotipo.toString();
	}
	
	public int getAptitud(){
		return aptitud;
	}
	
	public void recalcularAptitud(){
		int i = 0;
		boolean a0,a1,d0,d1,d2,d3,esperado,obtenido;
		a0=a1=d0=d1=d2=d3=true;
		int apt=0;
		while(i<64){
			d3 = !d3;
			if(i % 2 == 0)
				d2 = !d2;
			if(i % 4 == 0)
				d1 = !d1;
			if(i % 8 == 0)
				d0 = !d0;
			if(i % 16 == 0)
				a1 = !a1;
			if(i % 32 == 0)
				a0 = !a0;
//			System.out.print(genotipo.boolToBit(a0));
//			System.out.print(genotipo.boolToBit(a1)+"|");
//			System.out.print(genotipo.boolToBit(d0));
//			System.out.print(genotipo.boolToBit(d1));
//			System.out.print(genotipo.boolToBit(d2));
//			System.out.print(genotipo.boolToBit(d3)+"|");
			obtenido = genotipo.evaluar(a0, a1, d0, d1, d2, d3);
			if(a0 && a1)
				esperado = d0;
			else if(a0 && !a1)
				esperado = d1;
			else if(!a0 && a1)
				esperado = d2;
			else //if(!a0 && !a1)
				esperado = d3;
//			System.out.print(genotipo.boolToBit(esperado)+"|");
//			System.out.print(genotipo.boolToBit(obtenido)+"\t");
//			System.out.println(genotipo.toStringValues());
			i++;
			if(obtenido == esperado)
				apt++;
		}
//		return apt;
		int prof = genotipo.getProfundidad();
		if(prof>altura_max)
			apt -= (prof-altura_max)*10;
		aptitud = apt;
	}
	
	public void recalcularAptitud2(){
		int i = 0;
//		boolean a0,a1,d0,d1,d2,d3,esperado,obtenido;
		boolean a0,a1,a2,esperado,obtenido;
		boolean[] d = {true,true,true,true,true,true,true,true};
//		a0=a1=d0=d1=d2=d3=true;
		a0=a1=a2=true;
		int apt=0;
		while(i<2048){
			d[7] = !d[7];
			if(i % 2 == 0)
				d[6] = !d[6];
			if(i % 4 == 0)
				d[5] = !d[5];
			if(i % 8 == 0)
				d[4] = !d[4];
			if(i % 16 == 0)
				d[3] = !d[3];
			if(i % 32 == 0)
				d[2] = !d[2];
			if(i % 64 == 0)
				d[1] = !d[1];
			if(i % 128 == 0)
				d[0] = !d[0];
			if(i % 256 == 0)
				a2 = !a2;
			if(i % 512 == 0)
				a1 = !a1;
			if(i % 1024 == 0)
				a0 = !a0;
//			System.out.print(genotipo.boolToBit(a0));
//			System.out.print(genotipo.boolToBit(a1));
//			System.out.print(genotipo.boolToBit(a2)+"|");
//			System.out.print(genotipo.boolToBit(d[0]));
//			System.out.print(genotipo.boolToBit(d[1]));
//			System.out.print(genotipo.boolToBit(d[2]));
//			System.out.print(genotipo.boolToBit(d[3]));
//			System.out.print(genotipo.boolToBit(d[4]));
//			System.out.print(genotipo.boolToBit(d[5]));
//			System.out.print(genotipo.boolToBit(d[6]));
//			System.out.print(genotipo.boolToBit(d[7])+"|");
			obtenido = genotipo.evaluar2(a0, a1, a2, d);
			if(a0 && a1 && a2)
				esperado = d[0];
			else if(a0 && a1 && !a2)
				esperado = d[1];
			else if(a0 && !a1 && a2)
				esperado = d[2];
			else if(a0 && !a1 && !a2)
				esperado = d[3];
			else if(!a0 && a1 && a2)
				esperado = d[4];
			else if(!a0 && a1 && !a2)
				esperado = d[5];
			else if(!a0 && !a1 && a2)
				esperado = d[6];
			else 
				esperado = d[7];
//			if(a0 && a1)
//				esperado = d0;
//			else if(a0 && !a1)
//				esperado = d1;
//			else if(!a0 && a1)
//				esperado = d2;
//			else //if(!a0 && !a1)
//				esperado = d3;
//			System.out.print(genotipo.boolToBit(esperado)+"|");
//			System.out.print(genotipo.boolToBit(obtenido)+"\t");
//			System.out.println(genotipo.toStringValues());
			i++;
			if(obtenido == esperado)
				apt++;
		}
//		return apt;
		int prof = genotipo.getProfundidad();
//		if(prof>5)
//			System.out.println(prof);
		if(prof>altura_max)
			apt -= (prof-altura_max)*300;
		aptitud = apt;
	}
	
	static public String toString (boolean [] x){
		String s="";
		for(int i=0;i<x.length;i++){
			if(x[i])
				s+="1";
			else
				s+="0";
		}
		return s;
	}
	
	public int getProfundidad(){
		return genotipo.getProfundidad();
	}
	
	public static Comparator<Cromosoma> COMPARE_BY_FITNESS = new Comparator<Cromosoma>() {
        public int compare(Cromosoma c1, Cromosoma c2) {
        	return Double.compare(c1.getAptitud(), c2.getAptitud());
        }
    };
	
    public void rellenar(){
    	genotipo.rellenar(tipo_llenado,altura_max); 
    	recalcularAptitud();
    }
    
    public void cambiarHojaRandom(){
    	genotipo.cambiarHojaRandom();
    	recalcularAptitud();
    }
    
    public void cambiarNodoRandom(){
    	genotipo.cambiarNodoRandom();
    	recalcularAptitud();
    }
    
    public void cambiarArbolRandom(tipoLlenado tipo, int altura_max){
    	genotipo.cambiarArbolRandom(tipo,altura_max);
    	recalcularAptitud();
    }
    
    public void reemplazar(){
    	genotipo.reemplazar();
    }
    
    
    public void reemplazar2(){
    	genotipo.reemplazar2();
    }
    
    public Arbol getGenotipo(){
    	return genotipo;
    }
    
    public static void main(String[] args) {
    	Cromosoma c = new Cromosoma(tipoLlenado.COMPLETO,4);
    	c.rellenar();
    	System.out.println(c.getGenoString());
    	//System.out.println(c.getAptitud());
    	
    	c = new Cromosoma(tipoLlenado.COMPLETO,4);
    	c.rellenar();
    	System.out.println(c.getGenoString());
//    	System.out.println(c.getAptitud());
    	
    	c = new Cromosoma(tipoLlenado.COMPLETO,4);
    	c.rellenar();
    	System.out.println(c.getGenoString()+"\n");
//    	System.out.println(c.getAptitud());
    	
    	c = new Cromosoma(tipoLlenado.COMPLETO,3);
    	c.rellenar();
    	System.out.println(c.getGenoString());
    	//System.out.println(c.getAptitud());
    	
    	c = new Cromosoma(tipoLlenado.COMPLETO,3);
    	c.rellenar();
    	System.out.println(c.getGenoString());
//    	System.out.println(c.getAptitud());
    	
    	c = new Cromosoma(tipoLlenado.COMPLETO,3);
    	c.rellenar();
    	System.out.println(c.getGenoString());
//    	System.out.println(c.getAptitud());
    }
    	
}